package cn.yll.common.utils;

import cn.hutool.core.util.IdUtil;
import cn.yll.common.exception.BsErrEnum;
import cn.yll.common.exception.BsException;
import cn.yll.common.module.PayloadDto;
import com.alibaba.fastjson2.JSON;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;

import java.text.ParseException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * JWT工具类
 * @author yangll
 */
public class JwtTokenUtil {
    /** jwt加密 密钥 */
    private static final String SEC = "f37a8b6722dd77e073a53d47a0d31bf2";
    /**
     * jwt超时秒数
     */
    private static final long LOGIN_EXP_SECONDS = 3L * 3600L;

    /**
     * 创建jwt Token和刷新token
     * @param userId 登录的用户ID
     */
    public static Map<String, String> createTokens(Long userId) {
        String token = createJwtToken(userId);
        RedisUtil redisUtil = AppContextUtil.getBean(RedisUtil.class);
        redisUtil.set(IdUtil.fastSimpleUUID(), userId.toString(), 12 * LOGIN_EXP_SECONDS, TimeUnit.SECONDS);
        Map<String, String> map = new HashMap<>(2);
        map.put("token", token);
        map.put("refresh_token", token);
        return map;
    }

    /**
     * 创建jwt Token
     * @param userId 登录的用户ID
     */
    public static String createJwtToken(Long userId) {
        try {
            long time = Instant.now().getEpochSecond();
            PayloadDto dto = PayloadDto.builder().sub("login").iat(time).exp(time + LOGIN_EXP_SECONDS).userId(userId).build();
            JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JWT).build();
            Payload payload = new Payload(JSON.toJSONString(dto));
            JWSObject object = new JWSObject(header, payload);
            JWSSigner signer = new MACSigner(SEC);
            object.sign(signer);
            return object.serialize();
        } catch (JOSEException e) {
            throw new BsException(BsErrEnum.SYSTEM_ERROR, e);
        }
    }

    /**
     * 校验并获取jwt token负载信息
     * @param token  请求里的token
     */
    public static Long getUserIdByJwtToken(String token) {
        return getUserIdByPayload(getPayLoadByJwtToken(token));
    }

    /**
     * 校验并获取jwt token负载信息
     * @param token  请求里的token
     */
    public static PayloadDto getPayLoadByJwtToken(String token) {
        try {
            JWSObject object = JWSObject.parse(token);
            MACVerifier macVerifier = new MACVerifier(SEC);
            if (!object.verify(macVerifier)) {
                throw new BsException(BsErrEnum.TOKEN_ERROR);
            }
            String payload = object.getPayload().toString();
            PayloadDto dto = JSON.parseObject(payload, PayloadDto.class);
            if (dto.getExp() < Instant.now().getEpochSecond()) {
                throw new BsException(BsErrEnum.TOKEN_EXP);
            }
            return dto;
        } catch (ParseException | JOSEException e) {
            throw new BsException(BsErrEnum.TOKEN_ERROR, e);
        }
    }

    /**
     * 校验并获取用户ID
     * @param dto  请求里的token解析出来的用户数据
     */
    public static Long getUserIdByPayload(PayloadDto dto) {
        if (Objects.isNull(dto)) {
            return null;
        }
        return dto.getUserId();
    }

}
